package data

import (
	"context"
	"github.com/jiushengTech/common/utils/pageutil"
	"gorm.io/gorm"
	"reflect"
)

type BaseMapper[T any] struct{}

var db *gorm.DB

func InitBaseMapper(dataBase *gorm.DB) {
	db = dataBase
}

func (b BaseMapper[T]) Row(ctx context.Context, sql string, values ...any) *gorm.DB {
	return db.WithContext(ctx).Raw(sql)
}

func (b BaseMapper[T]) SaveOrUpdate(ctx context.Context, po T) *gorm.DB {
	// 假设T类型有一个名为ID的字段作为主键
	// 如果你的主键或唯一索引字段不是ID，你需要相应地修改下面的代码
	// 例如，你可以定义一个接口来获取用于查找的条件
	var idField interface{}
	var idValue interface{}

	// 使用反射获取ID字段的值
	v := reflect.ValueOf(po)
	idField = "ID" // 这里假设结构体有一个ID字段作为主键
	idValue = v.FieldByName("ID").Interface()

	// 创建一个查询条件
	condition := map[string]interface{}{idField.(string): idValue}

	// FirstOrCreate 会查找匹配的记录，如果找到则更新非零字段，如果未找到则创建新记录
	// 使用Assign来指定需要更新的字段
	// 注意: Assign在这里只有在创建记录时才会应用，更新时不会使用Assign中的值
	// 如果你想在更新时也只更新非零值，你需要自定义逻辑来构建一个只包含非零值字段的map
	return db.WithContext(ctx).Where(condition).Assign(po).FirstOrCreate(&po)
}

func (b BaseMapper[T]) Insert(ctx context.Context, po T) *gorm.DB {
	return b.DB(ctx).WithContext(ctx).WithContext(ctx).Create(&po)
}

func (b BaseMapper[T]) Delete(ctx context.Context, po T) *gorm.DB {
	return b.DB(ctx).WithContext(ctx).Delete(&po)
}

// 不会更新零值字段
func (b BaseMapper[T]) Updates(ctx context.Context, po T) *gorm.DB {
	return b.DB(ctx).WithContext(ctx).Updates(&po)
}

// 更新指定字段
func (b BaseMapper[T]) Update(ctx context.Context, column string, value interface{}) *gorm.DB {
	return b.DB(ctx).WithContext(ctx).Update(column, value)
}

// 会更新零值字段
func (b BaseMapper[T]) Save(ctx context.Context, po T) *gorm.DB {
	return b.DB(ctx).WithContext(ctx).Save(&po)
}

func (b BaseMapper[T]) List(ctx context.Context, po T) (res []T, d *gorm.DB) {
	return res, b.DB(ctx).WithContext(ctx).Find(&res, &po)
}

// GetOne 记录找不到，不会返回错误
func (b BaseMapper[T]) GetOne(ctx context.Context, po T) (res T, d *gorm.DB) {
	return res, b.DB(ctx).WithContext(ctx).Limit(1).Find(&res, &po)
}

// Detail 记录找不到，会返回错误
func (b BaseMapper[T]) Detail(ctx context.Context, po T) (res T, d *gorm.DB) {
	return res, b.DB(ctx).WithContext(ctx).First(&res, &po)
}

func (b BaseMapper[T]) BatchInsert(ctx context.Context, pos []T) *gorm.DB {
	return b.DB(ctx).WithContext(ctx).CreateInBatches(pos, len(pos))
}

func (b BaseMapper[T]) Page(ctx context.Context, db *gorm.DB, po *pageutil.PageQuery) (*pageutil.Page[T], error) {
	return pageutil.GetResult[T](b.DB(ctx).WithContext(ctx), po)
}
